package hexagon.security.core.domain;

import hexagon.security.core.NameIsExistedException;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.lang3.Validate;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Set;

/**
 * @author XueguiYuan
 * @version 1.0 (created time: 2016/12/3).
 */
@RequiredArgsConstructor
@Getter
@Setter
@ToString(of = {"name", "code", "description"})
@Entity
@Table(name = "authority")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public abstract class Authority extends SecurityAbstractEntity {

    @NotNull
    private String name;

    @NotNull
    private String code;

    private String description;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "authority_id")
    private List<Authorization> authorizations;

    public static final Finder<Long, Authority> find = new Finder<>(Authority.class);

    @Override
    public String[] businessKeys() {
        return new String[]{"name", "code"};
    }

    /**
     * 授权分配权限资源。
     *
     * @param securityResource 权限资源
     */
    public void addSecurityResource(SecurityResource securityResource) {
        new ResourceAssignment(this, securityResource).save();
    }

    /**
     * 授权分配多个权限资源。
     *
     * @param securityResources 权限资源集合
     */
    public void addSecurityResources(List<? extends SecurityResource> securityResources) {
        for (SecurityResource securityResource : securityResources) {
            this.addSecurityResource(securityResource);
        }
    }

    /**
     * 从授权中撤销权限资源。
     *
     * @param securityResource 权限资源
     */
    public void terminateSecurityResource(SecurityResource securityResource) {
        ResourceAssignment resourceAssignment = ResourceAssignment.findBySecurityResourceInAuthority(this, securityResource);
        if (resourceAssignment != null) {
            resourceAssignment.delete();
        }
    }

    /**
     * 从授权中撤销多个权限资源。
     *
     * @param securityResources 权限资源集合 {@link SecurityResource}
     */
    public void terminateSecurityResources(Set<? extends SecurityResource> securityResources) {
        for (SecurityResource securityResource : securityResources) {
            this.terminateSecurityResource(securityResource);
        }
    }

    /**
     * 改变授权的名称。
     *
     * @param name 授权名称
     */
    public void changeName(String name) {
        Validate.notBlank(name, "authority name cannot be empty.");
        if (!name.equals(this.getName())) {
            isExistedName(name);
            this.name = name;
            this.save();
        }
    }

    public List<SecurityResource> findSecurityResourceByAuthority() {
        return ResourceAssignment.findSecurityResourceByAuthority(this);
    }

    public List<SecurityResource> findSecurityResourceByAuthority(SecurityResource.SecurityResourceType type) {
        return ResourceAssignment.findSecurityResourceByAuthority(this, type);
    }

    private void isExistedName(String name) {
        if (find.where().eq("name", name).findCount() > 0) {
            throw new NameIsExistedException("authority name existed.");
        }
    }

}
